Skip to content

feat: add Google Gemini API proxy support (port 10003)#1640

Open
lpcox wants to merge 1 commit intomainfrom
feat/gemini-api-proxy-support
Open

feat: add Google Gemini API proxy support (port 10003)#1640
lpcox wants to merge 1 commit intomainfrom
feat/gemini-api-proxy-support

Conversation

@lpcox
Copy link
Copy Markdown
Collaborator

@lpcox lpcox commented Apr 3, 2026

Problem

Gemini CLI v0.65.0+ performs a startup auth check that exits with code 41 when GEMINI_API_BASE_URL is set but no GEMINI_API_KEY is found. In AWF mode, the real key should be held by the api-proxy sidecar (not exposed to the agent container), but no Gemini proxy endpoint exists — forcing gh-aw to work around the issue by injecting placeholder keys and mkdir commands into the container command string.

Additionally, ~/.gemini/ is not in AWF's whitelisted home subdirectories, causing an ENOENT when Gemini CLI attempts to save its project registry.

Upstream: github/gh-aw#23695 (gh-aw workaround for this gap)

Solution

Add full Gemini API proxy support following the same pattern as OpenAI, Anthropic, and Copilot providers:

API Proxy Sidecar (containers/api-proxy/)

  • Port 10003 — New Gemini proxy server in server.js
  • Reads GEMINI_API_KEY from env and injects it as x-goog-api-key header (Google API standard)
  • Supports configurable target (GEMINI_API_TARGET, default: generativelanguage.googleapis.com) and base path prefix (GEMINI_API_BASE_PATH)
  • Health check, rate limiting, and WebSocket upgrade support
  • Added to health response, startup log, and Dockerfile EXPOSE

CLI (src/cli.ts)

  • --gemini-api-target <host> and --gemini-api-base-path <path> flags
  • GEMINI_API_KEY read from env and passed to config
  • Gemini target auto-added to domain allowlist
  • Target validation warning via emitApiProxyTargetWarnings()

Docker Manager (src/docker-manager.ts)

  • GEMINI_API_KEY excluded from agent env when api-proxy enabled
  • GEMINI_API_KEY, GEMINI_API_TARGET, GEMINI_API_BASE_PATH passed to sidecar container
  • GEMINI_API_BASE_URL set in agent container pointing to sidecar (http://172.30.0.30:10003)
  • Placeholder GEMINI_API_KEY set in agent so Gemini CLI's startup auth check passes
  • .gemini added to whitelisted home subdirectories (bind mount + chroot dir creation)

Types (src/types.ts)

  • GEMINI: 10003 added to API_PROXY_PORTS
  • geminiApiKey, geminiApiTarget, geminiApiBasePath added to WrapperConfig

How it works

Gemini CLI (agent container)
  → GEMINI_API_BASE_URL=http://172.30.0.30:10003
  → Sends request with placeholder key
  → API proxy sidecar strips placeholder, injects real GEMINI_API_KEY
  → Routes through Squid (domain allowlist enforced)
  → generativelanguage.googleapis.com

Once this lands, the mkdir + placeholder workaround in gh-aw#23695 can be simplified — AWF will handle both the ~/.gemini/ directory and the credential isolation natively.

Testing

  • Build: ✅
  • Lint: ✅ (0 errors)
  • Unit tests: ✅ (322 CLI tests, 192 api-proxy tests pass)
  • Test update: Updated chroot home dir test to include .gemini

Add full Gemini API proxy support to the AWF api-proxy sidecar,
matching the pattern of existing OpenAI, Anthropic, and Copilot
providers. This enables Gemini CLI to work inside the AWF sandbox
without requiring workarounds in gh-aw.

Changes:
- Add GEMINI port 10003 to API_PROXY_PORTS
- Add geminiApiKey, geminiApiTarget, geminiApiBasePath to WrapperConfig
- Add --gemini-api-target and --gemini-api-base-path CLI flags
- Add GEMINI_API_KEY to excluded env vars when api-proxy is enabled
- Set placeholder GEMINI_API_KEY in agent container (Gemini CLI
  v0.65.0+ exits 41 without auth when GEMINI_API_BASE_URL is set)
- Set GEMINI_API_BASE_URL pointing to sidecar in agent env
- Add .gemini to whitelisted home subdirectories (bind mount + chroot)
- Add Gemini proxy server in server.js using x-goog-api-key header
- Expose port 10003 in Dockerfile

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 3, 2026 05:43
@lpcox lpcox requested a review from Mossaka as a code owner April 3, 2026 05:43
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 3, 2026

⚠️ Coverage Regression Detected

This PR decreases test coverage. Please add tests to maintain coverage levels.

Overall Coverage

Metric Base PR Delta
Lines 85.81% 85.64% 📉 -0.17%
Statements 85.69% 85.53% 📉 -0.16%
Functions 86.71% 86.71% ➡️ +0.00%
Branches 78.50% 78.02% 📉 -0.48%
📁 Per-file Coverage Changes (2 files)
File Lines (Before → After) Statements (Before → After)
src/docker-manager.ts 86.1% → 85.6% (-0.46%) 85.6% → 85.2% (-0.44%)
src/cli.ts 60.6% → 60.6% (+0.02%) 61.1% → 61.1% (+0.02%)

Coverage comparison generated by scripts/ci/compare-coverage.ts

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 3, 2026

Smoke test results (run 23935548933)

✅ GitHub MCP: feat(smoke-claude): trim unused tools / fix: token analyzers always run
✅ Playwright: GitHub page title verified
✅ File write: /tmp/gh-aw/agent/smoke-test-claude-23935548933.txt created
✅ Bash verify: file contents confirmed

Overall: PASS

💥 [THE END] — Illustrated by Smoke Claude

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 3, 2026

Chroot Version Comparison Results

Runtime Host Version Chroot Version Match?
Python Python 3.12.13 Python 3.12.3 ❌ NO
Node.js v24.14.0 v20.20.1 ❌ NO
Go go1.22.12 go1.22.12 ✅ YES

Overall: ❌ Not all tests passed — Python and Node.js versions differ between host and chroot environments.

Tested by Smoke Chroot for issue #1640

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 3, 2026

Smoke Test (Codex)
PR titles: feat(smoke-claude): trim unused tools to reduce token spend ~8%; docs: document implicit CLI behaviors (localhost keyword, enterprise auto-detection)

  1. GitHub MCP last 2 merged PRs: ✅
  2. safeinputs-gh PR query: ❌
  3. Playwright title contains "GitHub": ✅
  4. Tavily search returned items: ❌
  5. File write + cat readback: ✅
  6. Build (npm ci && npm run build): ✅
  7. Discussion interaction test: ❌
    Overall status: FAIL

🔮 The oracle has spoken through Smoke Codex

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Google Gemini support to the existing API-proxy sidecar pattern so Gemini CLI can run in AWF mode without exposing the real API key to the agent container, while also ensuring Gemini CLI state (~/.gemini) is persisted in chroot mode.

Changes:

  • Introduces a new Gemini proxy listener on port 10003 in the api-proxy sidecar, with support for custom target host/base-path and x-goog-api-key injection.
  • Extends CLI/config/types to support geminiApiKey, geminiApiTarget, and geminiApiBasePath and wires them into Docker Compose generation.
  • Adds ~/.gemini to the chroot home subdirectory allowlist and updates the corresponding test.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/types.ts Adds Gemini proxy port constant and new wrapper config fields for Gemini proxy settings.
src/docker-manager.ts Wires Gemini env handling between agent and sidecar; mounts ~/.gemini; creates chroot dir.
src/docker-manager.test.ts Updates expected chroot home subdirectories to include .gemini.
src/cli.ts Adds Gemini API target/base-path flags and reads GEMINI_API_KEY into config; adds target warning/allowlist support.
containers/api-proxy/server.js Adds Gemini proxy server on 10003 with key injection, health endpoint, and rate limiting.
containers/api-proxy/Dockerfile Exposes port 10003 in the sidecar image.
Comments suppressed due to low confidence (1)

src/cli.ts:1783

  • validateApiProxyConfig() / API-proxy status logging elsewhere in this file still only consider OpenAI/Anthropic/Copilot. With geminiApiKey now supported, running with only GEMINI_API_KEY will emit a misleading "no API keys found" warning and omit Gemini from the status output. Update the validation + status log to include Gemini.
      copilotGithubToken: process.env.COPILOT_GITHUB_TOKEN,
      geminiApiKey: process.env.GEMINI_API_KEY,
      copilotApiTarget: options.copilotApiTarget || process.env.COPILOT_API_TARGET,
      openaiApiTarget: options.openaiApiTarget || process.env.OPENAI_API_TARGET,
      openaiApiBasePath: options.openaiApiBasePath || process.env.OPENAI_API_BASE_PATH,

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 1777 to 1781
openaiApiKey: process.env.OPENAI_API_KEY,
anthropicApiKey: process.env.ANTHROPIC_API_KEY,
copilotGithubToken: process.env.COPILOT_GITHUB_TOKEN,
geminiApiKey: process.env.GEMINI_API_KEY,
copilotApiTarget: options.copilotApiTarget || process.env.COPILOT_API_TARGET,
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

geminiApiKey is now being added to the runtime config object, but the later redaction logic only excludes openaiApiKey, anthropicApiKey, and copilotGithubToken. This will cause GEMINI_API_KEY to be logged in debug output via redactedConfig (secret disclosure). Add geminiApiKey to the redaction skip list (and any other secret-handling paths).

This issue also appears on line 1779 of the same file.

Copilot uses AI. Check for mistakes.
Comment on lines +861 to +865

proxyRequest(req, res, GEMINI_API_TARGET, {
'x-goog-api-key': GEMINI_API_KEY,
}, 'gemini', GEMINI_API_BASE_PATH);
});
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gemini auth is injected via x-goog-api-key, but the proxy’s auth-safety/logging paths are still oriented around authorization/x-api-key. Consider adding x-goog-api-key to the stripped header set and including it in the auth_inject debug logic so client-supplied Gemini keys are consistently removed/overwritten and injection can be observed in logs.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 3, 2026

🔬 Smoke Test Results

PR: feat: add Google Gemini API proxy support (port 10003)
Author: @lpcox | Reviewers: @Mossaka, @Copilot

Test Result
GitHub MCP connectivity
GitHub.com HTTP connectivity
File write/read

Overall: PASS

📰 BREAKING: Report filed by Smoke Copilot

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 3, 2026

Smoke Test: GitHub Actions Services Connectivity ✅

All checks passed:

Service Check Result
Redis host.docker.internal:6379 PING +PONG
PostgreSQL host.docker.internal:5432 pg_isready accepting connections ✅
PostgreSQL smoketest db SELECT 1 1

🔌 Service connectivity validated by Smoke Services

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 3, 2026

🏗️ Build Test Suite Results

Ecosystem Project Build/Install Tests Status
Bun elysia 1/1 passed ✅ PASS
Bun hono 1/1 passed ✅ PASS
C++ fmt N/A ✅ PASS
C++ json N/A ✅ PASS
Deno oak N/A 1/1 passed ✅ PASS
Deno std N/A 1/1 passed ✅ PASS
.NET hello-world N/A ✅ PASS
.NET json-parse N/A ✅ PASS
Go color passed ✅ PASS
Go env passed ✅ PASS
Go uuid passed ✅ PASS
Java gson 1/1 passed ✅ PASS
Java caffeine 1/1 passed ✅ PASS
Node.js clsx passed ✅ PASS
Node.js execa passed ✅ PASS
Node.js p-limit passed ✅ PASS
Rust fd 1/1 passed ✅ PASS
Rust zoxide 1/1 passed ✅ PASS

Overall: 8/8 ecosystems passed — ✅ PASS

Generated by Build Test Suite for issue #1640 ·

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants